/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace GrooveWebServicesV12Controls
{
	/// <summary>
	/// Summary description for MemberAwarenessViewer.
	/// </summary>
	[System.Runtime.InteropServices.Guid("104B7730-DE65-3F33-80AE-D65A93CBE92D")]
	[System.Drawing.ToolboxBitmapAttribute(typeof(MemberAwarenessViewer), "MemberAwarenessViewer.ico")]
	public class MemberAwarenessViewer : System.Windows.Forms.UserControl
	{
		#region COM Registration Functions
		
		//  For more information, see Adam Nathan's book ".NET and COM", pp 471-477
		[System.Runtime.InteropServices.ComRegisterFunction]
		private static void ComRegisterFunction(System.Type i_Type)
		{
			Microsoft.Win32.RegistryKey CLSIDRegistryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("CLSID\\" + i_Type.GUID.ToString("B"), true);
			CLSIDRegistryKey.CreateSubKey("Control");
			CLSIDRegistryKey.CreateSubKey("Implemented Categories\\{40FC6ED4-2438-11CF-A3DB-080036F12502}");
			
			Microsoft.Win32.RegistryKey MiscStatusRegistryKey = CLSIDRegistryKey.CreateSubKey("MiscStatus");
			MiscStatusRegistryKey.SetValue("","131457");

			Microsoft.Win32.RegistryKey TypeLibRegistryKey = CLSIDRegistryKey.CreateSubKey("TypeLib");
			string TypeLibGuid = System.Runtime.InteropServices.Marshal.GetTypeLibGuidForAssembly(i_Type.Assembly).ToString("B");
			TypeLibRegistryKey.SetValue("", TypeLibGuid);

			string Version = i_Type.Assembly.GetName().Version.Major.ToString() + "." + i_Type.Assembly.GetName().Version.Minor.ToString();
			if (Version == "0.0")
				Version = "1.0";

			Microsoft.Win32.RegistryKey VersionRegistryKey = CLSIDRegistryKey.CreateSubKey("Version");
			VersionRegistryKey.SetValue("", Version);

			CLSIDRegistryKey.Close();
		}

		[System.Runtime.InteropServices.ComUnregisterFunction]
		private static void ComUnregisterFunction(System.Type i_Type)
		{
			try
			{
				Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + i_Type.GUID.ToString("B"));
			}
			catch (ArgumentException)
			{
				//  Ignore exception thrown if key doesn't exist
			}
		}

		#endregion

		private GrooveWebServicesV12Helpers.Context m_Context;

		private System.Collections.SortedList m_MemberTreeNodeSortedList;

		private GrooveWebServicesV12Helpers.Space m_Space;

		public System.Windows.Forms.TreeView TreeView;

		private System.Windows.Forms.ImageList imageList1;
		private System.ComponentModel.IContainer components;

		private System.EventHandler m_ContextMenuEventHandler;

		private System.Windows.Forms.ContextMenu m_ContextMenu;
		private System.Windows.Forms.MenuItem m_SendMessageMenuItem;
		private System.Windows.Forms.MenuItem m_InviteToWorkspaceMenuItem;
		private System.Windows.Forms.MenuItem m_InviteToInstantChatMenuItem;
		private System.Windows.Forms.MenuItem m_PropertiesMenuItem;

		private GrooveWebServicesV12Controls.MemberTreeNode m_CurrentMemberTreeNode;

		private delegate void AddMemberTreeNodeDelegate(GrooveWebServicesV12Helpers.Member i_Member);
		private delegate void UpdateMemberTreeNodeDelegate(GrooveWebServicesV12Helpers.Member i_Member, string i_ActiveInSpace);
		private delegate void RemoveMemberTreeNodeDelegate(string i_MemberURI);

		private AddMemberTreeNodeDelegate m_AddMemberTreeNodeDelegate;
		private UpdateMemberTreeNodeDelegate m_UpdateMemberTreeNodeDelegate;
		private RemoveMemberTreeNodeDelegate m_RemoveMemberTreeNodeDelegate;

		private System.Windows.Forms.TreeNode m_InWorkspaceMembersTreeNode;
		private System.Windows.Forms.TreeNode m_OnlineMembersTreeNode;
		private System.Windows.Forms.TreeNode m_NotOnlineMembersTreeNode;

		public MemberAwarenessViewer()
		{
			int_MemberAwarenessViewer(null);
		}

		public MemberAwarenessViewer(GrooveWebServicesV12Helpers.Context i_Context)
		{
			int_MemberAwarenessViewer(i_Context);
		}

		private void int_MemberAwarenessViewer(GrooveWebServicesV12Helpers.Context i_Context)
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();
        }

        public void Start()
        {
            Start(null);
        }

        public void Start(GrooveWebServicesV12Helpers.Context i_Context)
        {
            Start(null, false);
        }

        public void Start(GrooveWebServicesV12Helpers.Context i_Context, Boolean i_EnableContextMenu)
        {
			if (i_Context == null)
				m_Context = new GrooveWebServicesV12Helpers.Context();
			else
				m_Context = i_Context;
			
			m_MemberTreeNodeSortedList = new System.Collections.SortedList();

            if (i_EnableContextMenu)
            {
                //  Create context menu and menu items
                m_ContextMenuEventHandler = new System.EventHandler(ContextMenu_OnClick);
                m_SendMessageMenuItem = new System.Windows.Forms.MenuItem("Send Message...", m_ContextMenuEventHandler);
                m_InviteToWorkspaceMenuItem = new System.Windows.Forms.MenuItem("Invite to Workspace...", m_ContextMenuEventHandler);
                m_InviteToInstantChatMenuItem = new System.Windows.Forms.MenuItem("Invite to Instant Chat", m_ContextMenuEventHandler);
                m_PropertiesMenuItem = new System.Windows.Forms.MenuItem("Properties...", m_ContextMenuEventHandler);

                System.Windows.Forms.MenuItem[] MenuItems = { m_SendMessageMenuItem, m_InviteToWorkspaceMenuItem, m_InviteToInstantChatMenuItem, m_PropertiesMenuItem };
                m_ContextMenu = new System.Windows.Forms.ContextMenu(MenuItems);

                this.TreeView.SelectedImageIndex = 2;
            }

			m_AddMemberTreeNodeDelegate = new GrooveWebServicesV12Controls.MemberAwarenessViewer.AddMemberTreeNodeDelegate(AddMemberTreeNode);
			m_UpdateMemberTreeNodeDelegate = new GrooveWebServicesV12Controls.MemberAwarenessViewer.UpdateMemberTreeNodeDelegate(UpdateMemberTreeNode);
			m_RemoveMemberTreeNodeDelegate = new GrooveWebServicesV12Controls.MemberAwarenessViewer.RemoveMemberTreeNodeDelegate(RemoveMemberTreeNode);
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
					components.Dispose();

				//  Unsubscribe for Member events if necessary
				if (m_Space != null)
				{
					m_Space.OnMemberAddedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberAddedDelegate(Space_OnMemberAdded);
					m_Space.OnMemberUpdatedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberUpdatedDelegate(Space_OnMemberUpdated);
					m_Space.OnMemberRemovedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberRemovedDelegate(Space_OnMemberRemoved);
					m_Space.OnMemberAwarenessChangedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberAwarenessChangedDelegate(Space_OnMemberAwarenessChanged);
					//m_Space.OnMemberEnteredSpaceEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberEnteredSpaceDelegate(Space_OnMemberEnteredSpace);
					m_Space.OnMemberExitedSpaceEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberExitedSpaceDelegate(Space_OnMemberExitedSpace);
					m_Space.OnMemberEnteredToolEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberEnteredToolDelegate(Space_OnMemberEnteredTool);
					//m_Space.OnMemberExitedToolEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberExitedToolDelegate(Space_OnMemberExitedTool);
				}
			}
			base.Dispose( disposing );
		}
   
		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MemberAwarenessViewer));
			this.TreeView = new System.Windows.Forms.TreeView();
			this.imageList1 = new System.Windows.Forms.ImageList(this.components);
			this.SuspendLayout();
			// 
			// TreeView
			// 
			this.TreeView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
			this.TreeView.Dock = System.Windows.Forms.DockStyle.Fill;
			this.TreeView.HideSelection = false;
			this.TreeView.ImageList = this.imageList1;
			this.TreeView.Location = new System.Drawing.Point(0, 0);
			this.TreeView.Name = "TreeView";
			//this.TreeView.SelectedImageIndex = 2;
			this.TreeView.ShowLines = false;
			this.TreeView.ShowPlusMinus = false;
			this.TreeView.ShowRootLines = false;
			this.TreeView.Size = new System.Drawing.Size(208, 216);
			this.TreeView.TabIndex = 0;
			this.TreeView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TreeView_MouseDown);
			this.TreeView.DoubleClick += new System.EventHandler(this.TreeView_DoubleClick);
			this.TreeView.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.TreeView_BeforeSelect);
			// 
			// imageList1
			// 
			this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
			this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
			this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// MemberAwarenessViewer
			// 
			this.Controls.Add(this.TreeView);
			this.Name = "MemberAwarenessViewer";
			this.Size = new System.Drawing.Size(208, 216);
			this.Load += new System.EventHandler(this.MemberAwarenessViewer_Load);
			this.ResumeLayout(false);

		}
		#endregion

		[System.ComponentModel.Browsable(false)]
		public GrooveWebServicesV12Helpers.Space Space
		{
			get
			{
				return m_Space;
			}
			set
			{
				if ((value != null) && !this.DesignMode)
				{
					GrooveWebServicesV12Helpers.Space Space = (GrooveWebServicesV12Helpers.Space)value;
					
					//  See if we have already cached a reference to account
					if (m_Space != null)
					{
						//  If cached value is same as new value, just exit now
						if (m_Space.URI == Space.URI)
							return;

						//  Unsubscribe for Member events
						m_Space.OnMemberAddedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberAddedDelegate(Space_OnMemberAdded);
						m_Space.OnMemberUpdatedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberUpdatedDelegate(Space_OnMemberUpdated);
						m_Space.OnMemberRemovedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberRemovedDelegate(Space_OnMemberRemoved);
						m_Space.OnMemberAwarenessChangedEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberAwarenessChangedDelegate(Space_OnMemberAwarenessChanged);
						//m_Space.OnMemberEnteredSpaceEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberEnteredSpaceDelegate(Space_OnMemberEnteredSpace);
						m_Space.OnMemberExitedSpaceEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberExitedSpaceDelegate(Space_OnMemberExitedSpace);
						m_Space.OnMemberEnteredToolEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberEnteredToolDelegate(Space_OnMemberEnteredTool);
						//m_Space.OnMemberExitedToolEvent -= new GrooveWebServicesV12Helpers.Space.OnMemberExitedToolDelegate(Space_OnMemberExitedTool);

					}

					//  Cache reference to space and transceiver
					m_Space = value;

					//  Subscribe for member events
					m_Space.OnMemberAddedEvent += new GrooveWebServicesV12Helpers.Space.OnMemberAddedDelegate(Space_OnMemberAdded);
					m_Space.OnMemberUpdatedEvent += new GrooveWebServicesV12Helpers.Space.OnMemberUpdatedDelegate(Space_OnMemberUpdated);
					m_Space.OnMemberRemovedEvent += new GrooveWebServicesV12Helpers.Space.OnMemberRemovedDelegate(Space_OnMemberRemoved);
					m_Space.OnMemberAwarenessChangedEvent += new GrooveWebServicesV12Helpers.Space.OnMemberAwarenessChangedDelegate(Space_OnMemberAwarenessChanged);
					//m_Space.OnMemberEnteredSpaceEvent += new GrooveWebServicesV12Helpers.Space.OnMemberEnteredSpaceDelegate(Space_OnMemberEnteredSpace);
					m_Space.OnMemberExitedSpaceEvent += new GrooveWebServicesV12Helpers.Space.OnMemberExitedSpaceDelegate(Space_OnMemberExitedSpace);
					m_Space.OnMemberEnteredToolEvent += new GrooveWebServicesV12Helpers.Space.OnMemberEnteredToolDelegate(Space_OnMemberEnteredTool);
					//m_Space.OnMemberExitedToolEvent += new GrooveWebServicesV12Helpers.Space.OnMemberExitedToolDelegate(Space_OnMemberExitedTool);

					PopulateMembers();
				}
			}
		}

		private void PopulateMembers()
		{
			//  Clear treeview, sorted list and array list
			TreeView.Nodes.Clear();
			m_MemberTreeNodeSortedList.Clear();

			//  Create main tree nodes
			m_InWorkspaceMembersTreeNode = TreeView.Nodes.Add("In Workspace");
			m_InWorkspaceMembersTreeNode.ImageIndex = 4;
			m_OnlineMembersTreeNode = TreeView.Nodes.Add("Online");
			m_OnlineMembersTreeNode.ImageIndex = 4;
			m_NotOnlineMembersTreeNode = TreeView.Nodes.Add("Not Online");
			m_NotOnlineMembersTreeNode.ImageIndex = 4;

			//  Iterate through members
			GrooveWebServicesV12Helpers.Member[] Members = m_Space.Members;
			foreach (GrooveWebServicesV12Helpers.Member Member in Members)
			{
				Application.DoEvents();

				//  Asynchronously add Member tree node
				object[] Args = {Member};
				BeginInvoke(m_AddMemberTreeNodeDelegate, Args);
			}
		}

		private void AddMemberTreeNode(GrooveWebServicesV12Helpers.Member i_Member)
		{
			GrooveWebServicesV12Controls.MemberTreeNode MemberTreeNode = null;

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if found just exit now
				MemberTreeNode = (GrooveWebServicesV12Controls.MemberTreeNode)m_MemberTreeNodeSortedList[i_Member.URI];
				if (MemberTreeNode != null)
					return;

				MemberTreeNode = new GrooveWebServicesV12Controls.MemberTreeNode(i_Member);
				MemberTreeNode.Text = i_Member.Name;

				System.Windows.Forms.TreeNode TreeNode = null;

				if (i_Member.ActiveInSpace != null)
				{
					//  Modify ActiveInSpace uri if necessary
					string ActiveInSpaceURI = i_Member.ActiveInSpace;
					if (ActiveInSpaceURI.IndexOf("grooveTelespace://") != -1)
						ActiveInSpaceURI = ActiveInSpaceURI.Replace("grooveTelespace://", "grooveTelespace/");

					if (m_Space.URI.IndexOf(ActiveInSpaceURI) != -1)
					{
						MemberTreeNode.ImageIndex = 3;
						TreeNode = m_InWorkspaceMembersTreeNode;
					}
					else
					{
						MemberTreeNode.ImageIndex = 0;
						TreeNode = m_OnlineMembersTreeNode;
					}
				}
				else if (i_Member.Awareness == "Online")
				{
					MemberTreeNode.ImageIndex = 0;
					TreeNode = m_OnlineMembersTreeNode;
				}
				else if (i_Member.Awareness == "Offline")
				{
					MemberTreeNode.ImageIndex = 1;
					TreeNode = m_NotOnlineMembersTreeNode;
				}
				else
				{
					MemberTreeNode.ImageIndex = 0;
					TreeNode = m_OnlineMembersTreeNode;
				}

				int Index = 0;
				int NodeCount = TreeNode.Nodes.Count;

				//  Find insertion index
				for (Index = 0; Index < NodeCount; ++Index)
				{
					if (MemberTreeNode.Text.CompareTo(TreeNode.Nodes[Index].Text) < 0)
						break;
				}

				//  Insert node and make sure it is made visible
				TreeNode.Nodes.Insert(Index, MemberTreeNode);
				TreeNode.ExpandAll();

				//  Add new node to sorted list
				m_MemberTreeNodeSortedList[i_Member.URI] = MemberTreeNode;
			}
		}

		private void UpdateMemberTreeNode(GrooveWebServicesV12Helpers.Member i_Member, string i_ActiveInSpace)
		{
			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				GrooveWebServicesV12Controls.MemberTreeNode MemberTreeNode = (GrooveWebServicesV12Controls.MemberTreeNode)m_MemberTreeNodeSortedList[i_Member.URI];
				if (MemberTreeNode == null)
					return;

				//  Do nothing if state hasn't changed
				if (MemberTreeNode.ActiveInSpace == i_ActiveInSpace)
					return;

				if (!System.String.IsNullOrEmpty(i_Member.Name))
					MemberTreeNode.Text = i_Member.Name;

				//  Remove tree node
				MemberTreeNode.Remove();

				System.Windows.Forms.TreeNode TreeNode = null;

				if (i_ActiveInSpace != null)
				{
					if (m_Space.URI.IndexOf(i_ActiveInSpace) != -1)
					{
						MemberTreeNode.ImageIndex = 3;
						TreeNode = m_InWorkspaceMembersTreeNode;
					}
					else
					{
						MemberTreeNode.ImageIndex = 0;
						TreeNode = m_OnlineMembersTreeNode;
					}
				}
				else if (i_Member.Awareness == "Online")
				{
					MemberTreeNode.ImageIndex = 0;
					TreeNode = m_OnlineMembersTreeNode;
				}
				else if (i_Member.Awareness == "Offline")
				{
					MemberTreeNode.ImageIndex = 1;
					TreeNode = m_NotOnlineMembersTreeNode;
				}
				else
				{
					MemberTreeNode.ImageIndex = 0;
					TreeNode = m_OnlineMembersTreeNode;
				}

				MemberTreeNode.ActiveInSpace = i_ActiveInSpace;

				int Index = 0;
				int NodeCount = TreeNode.Nodes.Count;

				//  Find insertion index
				for (Index = 0; Index < NodeCount; ++Index)
				{
					if (MemberTreeNode.Text.CompareTo(TreeNode.Nodes[Index].Text) < 0)
						break;
				}

				//  Insert node and make sure it is made visible
				TreeNode.Nodes.Insert(Index, MemberTreeNode);
				TreeNode.ExpandAll();
			}
		}

		private void RemoveMemberTreeNode(string i_MemberURI)
		{
			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_MemberURI] == null)
					return;

				//  Remove tree node
				System.Windows.Forms.TreeNode TreeNode = (System.Windows.Forms.TreeNode)m_MemberTreeNodeSortedList[i_MemberURI];
				TreeNode.Remove();

				//  Remove node from sorted list
				m_MemberTreeNodeSortedList.Remove(i_MemberURI);
			}
		}

		private void MemberAwarenessViewer_Load(object sender, System.EventArgs e)
		{
			if (this.DesignMode)
			{
				//  Create mockup tree
				m_InWorkspaceMembersTreeNode = TreeView.Nodes.Add("InWorkspace");
				m_InWorkspaceMembersTreeNode.ImageIndex = 4;
				m_OnlineMembersTreeNode = TreeView.Nodes.Add("Online");
				m_OnlineMembersTreeNode.ImageIndex = 4;
				m_NotOnlineMembersTreeNode = TreeView.Nodes.Add("Not Online");
				m_NotOnlineMembersTreeNode.ImageIndex = 4;

				System.Windows.Forms.TreeNode MemberTreeNode = new System.Windows.Forms.TreeNode("John Smith");
				MemberTreeNode.ImageIndex = 3;
				m_InWorkspaceMembersTreeNode.Nodes.Add(MemberTreeNode);

				MemberTreeNode = new System.Windows.Forms.TreeNode("Bubba Jones");
				MemberTreeNode.ImageIndex = 0;
				m_OnlineMembersTreeNode.Nodes.Add(MemberTreeNode);

				MemberTreeNode = new System.Windows.Forms.TreeNode("Susan Smith");
				MemberTreeNode.ImageIndex = 1;
				m_NotOnlineMembersTreeNode.Nodes.Add(MemberTreeNode);

				TreeView.ExpandAll();
			}
			else
			{
			}
		}

		private void ContextMenu_OnClick(object sender, EventArgs e)
		{
			System.Windows.Forms.MenuItem MenuItem = (System.Windows.Forms.MenuItem)sender;
			switch (MenuItem.Index)
			{
				//  Send Message
				case 0:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.OpenSendInstantMessageWindow(m_CurrentMemberTreeNode.Member);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("TransceiverSendInstantMessage failed: " + ex.Message);
					}

					break;
				}

				//  Invite to Chat
				case 2:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.SendInvitationToChat
							(
							m_Space.Identity,
							m_CurrentMemberTreeNode.Member
							);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("SendInvitationToChat failed: " + ex.Message);
					}

					break;
				}

				//  Properties
				case 3:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.OpenContactPropertiesViewer(m_CurrentMemberTreeNode.Member);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("OpenVCardViewer failed: " + ex.Message);
					}

					break;
				}

				default:
				{
					break;
				}
			}
		}

		private void InviteToSpaceMenuItem_OnClick(object sender, EventArgs e)
		{
			GrooveWebServicesV12Controls.SpaceMenuItem SpaceMenuItem = (GrooveWebServicesV12Controls.SpaceMenuItem)sender;

			try
			{
				GrooveWebServicesV12Helpers.Local.OpenSendInvitationWindow(m_CurrentMemberTreeNode.Member.Space);
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine("SendInvitation failed: " + ex.Message);
			}
		}

		#region Member Event Handlers

		private void Space_OnMemberAdded(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberAdded: " + i_Member.URI);
			
			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] != null)
					return;

				//  Get Member tree node
				GrooveWebServicesV12Controls.MemberTreeNode MemberTreeNode = (GrooveWebServicesV12Controls.MemberTreeNode)m_MemberTreeNodeSortedList[i_Member.URI];

				//  Asynchronously add Member tree node
				object[] Args = {i_Member};
				BeginInvoke(m_AddMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberUpdated(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberUpdated: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;

				//  Get Member tree node
				GrooveWebServicesV12Controls.MemberTreeNode MemberTreeNode = (GrooveWebServicesV12Controls.MemberTreeNode)m_MemberTreeNodeSortedList[i_Member.URI];

				//  Asynchronously update Member tree node
				object[] Args = {i_Member, i_Member.ActiveInSpace};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberRemoved(string i_MemberURI)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberRemoved: " + i_MemberURI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_MemberURI] == null)
					return;
			
				//  Asynchronously remove Member tree node
				object[] Args = {i_MemberURI};
				BeginInvoke(m_RemoveMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberAwarenessChanged(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberAwarenessChanged: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;
			
				//  Asynchronously update Member tree node
				object[] Args = {i_Member, i_Member.ActiveInSpace};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberEnteredSpace(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberEnteredSpace: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;
							
				//  Asynchronously update Member tree node
				object[] Args = {i_Member, m_Space.URI};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberExitedSpace(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberExitedSpace: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;

				//  Asynchronously update Member tree node
				object[] Args = {i_Member, i_Member.ActiveInSpace};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberEnteredTool(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberEnteredTool: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;
				
				//  Asynchronously update Member tree node
				object[] Args = {i_Member, m_Space.URI};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		private void Space_OnMemberExitedTool(GrooveWebServicesV12Helpers.Member i_Member)
		{
			System.Diagnostics.Debug.WriteLine("OnMemberExitedTool: " + i_Member.URI);

			lock (m_MemberTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_MemberTreeNodeSortedList[i_Member.URI] == null)
					return;

				//  Asynchronously update Member tree node
				object[] Args = {i_Member, i_Member.ActiveInSpace};
				BeginInvoke(m_UpdateMemberTreeNodeDelegate, Args);
			}
		}

		#endregion

		private void TreeView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			System.Windows.Forms.TreeNode TreeNode = TreeView.GetNodeAt(e.X, e.Y);
			if (TreeNode == null)
				return;

			TreeView.SelectedNode = TreeNode;
			m_CurrentMemberTreeNode = (GrooveWebServicesV12Controls.MemberTreeNode)TreeNode;

            if (e.Button == System.Windows.Forms.MouseButtons.Right && m_ContextMenu != null)
			{
				//  Remove existing invite to space menu item and 
				//  reconstruct it
				m_ContextMenu.MenuItems.Remove(m_InviteToWorkspaceMenuItem);

				m_InviteToWorkspaceMenuItem = new System.Windows.Forms.MenuItem("Invite to Workspace", m_ContextMenuEventHandler);
				m_ContextMenu.MenuItems.Add(1, m_InviteToWorkspaceMenuItem);

				//  Get list of spaces and populate submenu items
				GrooveWebServicesV12Helpers.Space[] Spaces = m_Space.Identity.StandardSpaces;
				foreach (GrooveWebServicesV12Helpers.Space Space in Spaces)
				{
					GrooveWebServicesV12Controls.SpaceMenuItem SpaceMenuItem = new GrooveWebServicesV12Controls.SpaceMenuItem(Space);
					SpaceMenuItem.Click += new System.EventHandler(InviteToSpaceMenuItem_OnClick);
					m_InviteToWorkspaceMenuItem.MenuItems.Add(SpaceMenuItem);
				}

				m_ContextMenu.Show(TreeView, new System.Drawing.Point(e.X, e.Y));
			}
		}

		private void TreeView_BeforeSelect(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
		{
			//  Cancel operation if root node selected
			e.Cancel = 
				(e.Node == m_InWorkspaceMembersTreeNode) ||
				(e.Node == m_OnlineMembersTreeNode) ||
				(e.Node == m_NotOnlineMembersTreeNode);
		}

		private void TreeView_DoubleClick(object sender, System.EventArgs e)
		{
            if (m_ContextMenu != null)
            {
                try
                {
                    GrooveWebServicesV12Helpers.Local.OpenSendInstantMessageWindow(m_CurrentMemberTreeNode.Member);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("OpenSendInstantMessageWindow failed: " + ex.Message);
                }
            }
		}
	}
}
